package com.yingxin.yxerp.module.permission.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yingxin.yx.framework.commons.constant.CommonConst;
import com.yingxin.yx.framework.commons.enums.BusinessType;
import com.yingxin.yx.framework.commons.exception.BizException;
import com.yingxin.yx.framework.user.core.IUserSupport;
import com.yingxin.yxerp.module.oplog.aop.OplogAnnotation;
import com.yingxin.yxerp.module.permission.entity.*;
import com.yingxin.yxerp.module.permission.mapper.RoleMapper;
import com.yingxin.yxerp.module.permission.service.*;
import com.yingxin.yxerp.module.permission.vo.req.helper.UserAppPermissionTreeHelper;
import com.yingxin.yxerp.module.permission.vo.req.helper.UserPermissionTreeHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 角色 服务实现类
 * </p>
 *
 * @author fanchao
 * @since 2021-05-13
 */
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {

    @Autowired
    private IRolePermissionService rolePermissionService;

    @Autowired
    private IPermissionService permissionService;

    @Autowired
    private IUserSupport userSupport;

    @Autowired
    private IAppPermissionService appPermissionService;

    @Autowired
    private IAppRolePermissionService appRolePermissionService;



    /**
     * 根据 roleIds 查询
     *
     * @param roleIds
     * @return
     */
    /**
     @Override public List<Role> listByRoleIds(Collection<String> roleIds) {
     QueryWrapper<Role> qw = new QueryWrapper<>();
     qw.lambda().in(Role::getId, roleIds);
     // qw.lambda().eq(Role::getStatus, CommonConst.TRUE);
     return list(qw);
     }
     */

    /**
     * 新增角色
     *
     * @param role
     * @param permissionIds
     */

    @OplogAnnotation(biz = BusinessType.ROLE, id = "{{role.id}}", action = "新增",
            desc = "角色[{{role.name}}]")
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void create(Role role, List<String> permissionIds) {
        checkRoleName(role.getName(), role.getId());
        save(role);
        saveRolePermission(role, permissionIds);
    }

    /**
     * 修改角色
     *
     * @param role
     * @param permissionIds
     */
    @OplogAnnotation(biz = BusinessType.ROLE, id = "{{role.id}}", action = "修改",
            desc = "角色[{{role.name}}]")
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void update(Role role, List<String> permissionIds) {
        checkRoleName(role.getName(), role.getId());
        updateById(role);
        rolePermissionService.deleteByRoleId(role.getId());
        saveRolePermission(role, permissionIds);
        // 激活权限加载
        userSupport.activateReloadPermissions();
    }

    /**
     * 新增角色
     *
     * @param role
     * @param permissionIds
     */

    @OplogAnnotation(biz = BusinessType.ROLE, id = "{{role.id}}", action = "新增",
            desc = "角色[{{role.name}}]")
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void appCreate(Role role, List<String> permissionIds) {
        checkRoleName(role.getName(), role.getId());
        save(role);
        saveAppRolePermission(role, permissionIds);
    }

    /**
     * app修改角色
     *
     * @param role
     * @param permissionIds
     */
    @OplogAnnotation(biz = BusinessType.ROLE, id = "{{role.id}}", action = "修改",
            desc = "角色[{{role.name}}]")
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void appUpdate(Role role, List<String> permissionIds) {
        checkRoleName(role.getName(), role.getId());
        updateById(role);
        appRolePermissionService.deleteByRoleId(role.getId());
        saveAppRolePermission(role, permissionIds);
        // 激活权限加载
        //userSupport.activateReloadPermissions();
    }

    /**
     * 启用角色
     */
    @OplogAnnotation(biz = BusinessType.ROLE, id = "{{role.id}}", action = "启用",
            desc = "角色[{{role.name}}]")
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void enable(Role role) {
        UpdateWrapper<Role> uw = new UpdateWrapper<>();
        uw.lambda().set(Role::getStatus, CommonConst.TRUE);
        uw.lambda().eq(Role::getId, role.getId());
        boolean success = update(uw);
        if (!success) {
            throw new BizException("操作失败");
        }
        // 激活权限加载
        userSupport.activateReloadPermissions();
    }

    /**
     * 禁用角色
     */
    @OplogAnnotation(biz = BusinessType.ROLE, id = "{{role.id}}", action = "禁用",
            desc = "角色[{{role.name}}]")
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void disable(Role role) {
        UpdateWrapper<Role> uw = new UpdateWrapper<>();
        uw.lambda().set(Role::getStatus, CommonConst.FALSE);
        uw.lambda().eq(Role::getId, role.getId());
        boolean success = update(uw);
        if (!success) {
            throw new BizException("操作失败");
        }
        // 激活权限加载
        userSupport.activateReloadPermissions();
    }

    /**
     * 删除角色
     */
    @OplogAnnotation(biz = BusinessType.ROLE, id = "{{role.id}}", action = "删除",
            desc = "角色[{{role.name}}]")
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void delete(Role role) {
        removeById(role.getId());
        rolePermissionService.deleteByRoleId(role.getId());
        // 激活权限加载
        userSupport.activateReloadPermissions();
    }

    /**
     * saveRolePermission
     */
    private void saveRolePermission(Role role, List<String> permissionIds) {
        if (CollectionUtil.isNotEmpty(permissionIds)) {
            // rolePermissionMap
            Map<String, RolePermission> rolePermissionMap = new HashMap<>();
            for (String permissionId : permissionIds) {
                rolePermissionMap.put(permissionId, new RolePermission(role.getId(), permissionId));
            }
            // parent
            List<Permission> permissions = permissionService.list();
            Collection<Permission> parentPermissions = UserPermissionTreeHelper.buildParent(rolePermissionMap, permissions);
            for (Permission parent : parentPermissions) {
                rolePermissionMap.put(parent.getId(), new RolePermission(role.getId(), parent.getId()));
            }
            rolePermissionService.saveBatch(rolePermissionMap.values());
        }
    }

    /**
     * app保存角色权限
     * @param role
     * @param permissionIds
     */
    private void saveAppRolePermission(Role role, List<String> permissionIds) {
        if (CollectionUtil.isNotEmpty(permissionIds)) {
            // rolePermissionMap
            Map<String, AppRolePermission> rolePermissionMap = new HashMap<>();
            for (String permissionId : permissionIds) {
                rolePermissionMap.put(permissionId, new AppRolePermission(role.getId(), permissionId));
            }
            // parent
            List<AppPermission> permissions = appPermissionService.list();
            Collection<AppPermission> parentPermissions = UserAppPermissionTreeHelper.buildParent(rolePermissionMap, permissions);
            for (AppPermission parent : parentPermissions) {
                rolePermissionMap.put(parent.getId(), new AppRolePermission(role.getId(), parent.getId()));
            }
            appRolePermissionService.saveBatch(rolePermissionMap.values());
        }
    }

    public void checkRoleName(String name, String excludeId) {
        QueryWrapper<Role> qw = new QueryWrapper<>();
        qw.lambda().eq(Role::getName, name);
        if (excludeId != null) {
            qw.lambda().ne(Role::getId, excludeId);
        }
        List<Role> list = list(qw);
        if (list.size() > 0) {
            throw new BizException("名称重复");
        }
    }

}